package org.tloss.web.editor.projects;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.Properties;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.ui.PreferenceConstants;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.dialogs.WizardNewProjectCreationPage;
import org.tloss.web.editor.Utils;
import org.tloss.web.editor.utils.Constants;

public class WebEditorProjectWizard extends Wizard implements INewWizard {
	private WizardNewProjectCreationPage _pageOne;

	public void addPages() {
		super.addPages();

		_pageOne = new WizardNewProjectCreationPage("WebEditor Project Wizard");
		_pageOne.setTitle("WebEditor Project Wizard");
		_pageOne.setDescription("WebEditor Project Wizard");

		addPage(_pageOne);
	}

	public WebEditorProjectWizard() {

	}

	@Override
	public void init(IWorkbench workbench, IStructuredSelection selection) {

	}

	@Override
	public boolean performFinish() {

		String name = _pageOne.getProjectName();
		URI location = null;
		if (!_pageOne.useDefaults()) {
			location = _pageOne.getLocationURI();
		} // else location == null

		createProject(name, location);
		return true;
	}

	private IProject createBaseProject(String projectName, URI location) {

		// it is acceptable to use the ResourcesPlugin class
		IProject newProject = ResourcesPlugin.getWorkspace().getRoot()
				.getProject(projectName);

		if (!newProject.exists()) {
			URI projectLocation = location;
			IProjectDescription desc = newProject.getWorkspace()
					.newProjectDescription(newProject.getName());
			if (location != null
					& ResourcesPlugin.getWorkspace().getRoot().getLocationURI()
							.equals(location)) {
				projectLocation = null;
			}

			desc.setLocationURI(projectLocation);
			try {
				newProject.create(desc, null);
				if (!newProject.isOpen()) {
					newProject.open(null);
				}
			} catch (CoreException e) {
				Utils.logError(e);
			}
		}

		return newProject;

	}

	private void addNature(IProject project, IProgressMonitor monitor)
			throws CoreException {
		if (!project.hasNature(WebEditorNature.ID)) {
			IProjectDescription description = project.getDescription();
			String[] prevNatures = description.getNatureIds();
			String[] newNatures = new String[prevNatures.length + 1];
			System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length);
			newNatures[prevNatures.length] = WebEditorNature.ID;
			description.setNatureIds(newNatures);

			project.setDescription(description, monitor);
		}
	}

	public static IJavaProject getJavaProjectBatched(final IProject project,
			final String sourceFolderPath, final String binFolderPath,
			IProgressMonitor monitor) throws CoreException {
		IWorkspaceRunnable r = new IWorkspaceRunnable() {
			@Override
			public void run(IProgressMonitor monitor) throws CoreException {
				if (project.exists()) {

					IProjectDescription description = project.getDescription();
					String[] natureIds = description.getNatureIds();
					if (natureIds != null && natureIds.length > 0) {
						String[] newNatureIds = Arrays.copyOf(natureIds,
								natureIds.length + 1);
						newNatureIds[natureIds.length] = JavaCore.NATURE_ID;
						description.setNatureIds(newNatureIds);
					} else {
						description
								.setNatureIds(new String[] { JavaCore.NATURE_ID });
					}
					project.setDescription(description, monitor);

					IFolder binFolder = project.getFolder(binFolderPath);
					binFolder.create(false, true, monitor);
					final IFolder sourceFolder = project
							.getFolder(sourceFolderPath);
					sourceFolder.create(false, true, monitor);

					final IJavaProject javaProject = JavaCore.create(project);
					javaProject.setOutputLocation(binFolder.getFullPath(),
							monitor);

					IPackageFragmentRoot root = javaProject
							.getPackageFragmentRoot(sourceFolder);

					IClasspathEntry[] jre = PreferenceConstants
							.getDefaultJRELibrary();

					if (jre != null && jre.length > 0) {
						IClasspathEntry[] newEntries = Arrays.copyOf(jre,
								jre.length + 1);
						newEntries[jre.length] = JavaCore.newSourceEntry(root
								.getPath());
						javaProject.setRawClasspath(newEntries, monitor);
					} else {
						IClasspathEntry[] newEntries = new IClasspathEntry[1];
						newEntries[0] = JavaCore.newSourceEntry(root.getPath());
						javaProject.setRawClasspath(newEntries, monitor);
					}

				}
			}
		};

		project.getWorkspace().run(r, null, IWorkspace.AVOID_UPDATE, monitor);
		IJavaProject javaProject = JavaCore.create(project);
		return javaProject;
	}

	private void createFolder(IFolder folder, IProgressMonitor monitor)
			throws CoreException {
		IContainer parent = folder.getParent();
		if (parent instanceof IFolder) {
			createFolder((IFolder) parent, monitor);
		}
		if (!folder.exists()) {
			folder.create(false, true, monitor);
		}
	}

	private void addToProjectStructure(IProject newProject, String[] paths,
			IProgressMonitor monitor) throws CoreException {
		for (String path : paths) {
			IFolder etcFolders = newProject.getFolder(path);
			createFolder(etcFolders, monitor);
		}
	}

	private void createProject(final String projectName, final URI location) {
		Assert.isNotNull(projectName);
		Assert.isTrue(projectName.trim().length() > 0);
		Job job = new Job("Create Project") {
			protected IStatus run(IProgressMonitor monitor) {
				IProject project = createBaseProject(projectName, location);
				try {
					addNature(project, monitor);

					String[] paths = { Constants.ENTITY_FOLDER,
							Constants.SQL_FOLDER, Constants.FORMS_FOLDER,
							Constants.DATABASE_FOLDER,
							Constants.CONFIGURATION_FOLDER }; //$NON-NLS-1$ //$NON-NLS-2$
					addToProjectStructure(project, paths, monitor);
					IFolder folder = Utils.createFolder(project,
							Constants.CONFIGURATION_FOLDER, monitor);
					if (folder != null) {
						Properties properties = new Properties();
						properties.setProperty("BEANFACTORY",
								"org.tloss.web.spring.BeanFactory");
						properties.setProperty("CONVERTOR",
								"org.tloss.web.Convertor");
						properties.setProperty("SRC_FOLDER", "src");
						properties
								.setProperty("SRC_RESOURCE_FOLDER_PRO", "src");
						ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
						properties.store(arrayOutputStream, "");

						ByteArrayInputStream input = new ByteArrayInputStream(
								arrayOutputStream.toByteArray());
						Utils.createFile(folder,
								Constants.CONFIGURATION_SAMPLE_FILE, monitor,
								input);
					}
					getJavaProjectBatched(project, Constants.SRC_FOLDER, "bin",
							monitor);

				} catch (CoreException e) {
					Utils.logError(e);
					project = null;
					return Status.CANCEL_STATUS;
				} catch (IOException e) {
					Utils.logError(e);
					project = null;
					return Status.CANCEL_STATUS;
				}
				return Status.CANCEL_STATUS;
			}

		};
		job.setPriority(Job.LONG);
		job.schedule();
	}
}
